package store;

import java.util.Comparator;
import org.jdom.Element;
import dataview.InfoCibo;
import dataview.Termini;
import dataview.Unita;
import dataview.Valore;
import dataview.CiboVis;
import dataview.CiboVisCorta;
import dataview.Valori;
import exceptions.XmlException;

public class Cibo {
	private String nome;
	private InfoCibo info;
	private Termini tag;
	
	private Cibo() {
		tag = new Termini();
	}
	
	public Cibo(String nome, InfoCibo info, Termini tag) {
		super();
		this.nome = nome;
		this.info = info;
		this.tag = tag;
	}
	
	public CiboVis vis() {
		return new CiboVis(this);
	}
	
	public CiboVisCorta visCorta() {
		if (info != null) return new CiboVisCorta(nome, info.getDescrizione());
		return new CiboVisCorta(nome, null);
	}
	
	public boolean modifica(InfoCibo info, Termini tag) {
		if (this.info.equals(info) && this.tag.equals(tag)) return false;
		this.info = info;
		this.tag = tag;
		return true;
	}
	
	public String getNome() {
		return nome;
	}
	
	protected void setNome(String nome) {
		this.nome = nome;
	}
	
	public InfoCibo getInfo() {
		return info;
	}
	
	public Termini getTag() {
		return tag;
	}
	
	/**
	 * Restituisce l'elemento xml corrispondente al cibo in questione
	 */
	public Element toXml() {
		Element cibo = new Element("cibo");
		cibo.setAttribute("nome", nome);
		if (info.getDescrizione() != null) cibo.addContent(new Element("descrizione").setText(info.getDescrizione()));
		if (tag != null && !tag.isEmpty()) cibo.addContent(tag.getFirst().toXml());
		
		if (info.getUnitaRiferimento() != null) cibo.addContent(info.getUnitaRiferimento().toXml());
		cibo.addContent(new Element("numero_calorie").setText(Integer.toString(info.getCalXunita())));
		
		if (info.getValori() != null && !info.getValori().isEmpty()) {
			Element analisi = new Element("analisi");
			for (Valore valore : info.getValori())
				analisi.addContent(valore.toXml());
			cibo.addContent(analisi);
		}
		return cibo;
	}
	
	/**
	 * Costruttore di un Cibo
	 * 
	 * @param cibo Elemento xml che rappresenta un cibo
	 * @return L'oggetto Cibo rappresentante l'elemento xml passato come parametro
	 * @throws XmlException Se l'elemento passato non rappresenta un cibo
	 */
	public static Cibo fromXml(Element cibo) throws XmlException {
		if (cibo.getName() != "cibo") throw new XmlException("L'elemento passato non rappresenta un cibo");
		
		Cibo newCibo = new Cibo();
		String descrizione;
		int calorie = 0;
		Unita unita = null;
		Valori valori = new Valori();
		Element e;
		
		newCibo.nome = cibo.getAttributeValue("nome");
		descrizione = cibo.getChildText("descrizione");
		newCibo.tag.add(Termine.fromXml(cibo.getChild("genere_cibo")));
		
		calorie = Integer.parseInt(cibo.getChildText("numero_calorie"));
		if ((e = cibo.getChild("unita")) != null) unita = Unita.fromXml(e);
		
		if ((e = cibo.getChild("analisi")) != null) {
			for (Object el : e.getChildren("valore"))
				valori.add(Valore.fromXml((Element)el));
		}
		newCibo.info = new InfoCibo(descrizione, calorie, unita, valori);
		
		return newCibo;
	}
	
	@Override
	public String toString() {
		return nome;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((nome == null) ? 0 : nome.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		if (getClass() != obj.getClass()) return false;
		Cibo other = (Cibo)obj;
		if (nome == null) {
			if (other.nome != null) return false;
		} else if (!nome.equalsIgnoreCase(other.nome)) return false;
		return true;
	}
	
	/**
	 * Restituisce il comparatore per gli oggetti di tipo Cibo
	 * 
	 * @param ordine_crescente Se vero viene restituito il comporatore per mantenere l'ordine
	 *        crescente, decrescente altrimenti
	 * @return Restituisce il comparatore per gli oggetti di tipo Cibo
	 */
	public static Comparator<Cibo> getComparator(boolean ordine_crescente) {
		final boolean o = ordine_crescente;
		return new Comparator<Cibo>() {
			@Override
			public int compare(Cibo o1, Cibo o2) {
				if (o)
					return o1.getNome().compareToIgnoreCase(o2.getNome());
				else return o2.getNome().compareToIgnoreCase(o1.getNome());
			}
		};
	}
}